﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using XFControls.XFPanels.XFPanelItems;
using System.Threading;

namespace XFControls.XFPanels
{
    public partial class XFPanelList : XFPanelBase
    {
        public IXFItem HeaderItem { get; private set; }
        protected List<IXFItem> _items;
        protected Dictionary<IXFItem, XFItemAnimation> _animationItems;


        public XFPanelList()
        {
            InitializeComponent();
            _items = new List<IXFItem>();
            _animationItems = new Dictionary<IXFItem, XFItemAnimation>();

            Width = Screen.PrimaryScreen.WorkingArea.Width;
        }

        public override void Reset()
        {
            int height = 0;
            foreach (var itm in _items)
            {
                if (itm.Buffer != null)
                    itm.Buffer.Dispose();

                itm.Buffer = null;

                itm.ResetHeight();
                height += itm.GetHeight();
            }
            setHeight(height);
            base.Reset();
        }

        public void Resize()
        {
            int height = 0;
            foreach (var itm in _items)
            {
                height += itm.GetHeight();
            }
            setHeight(height);
        }

        public int this[IXFItem itm]
        {
            get { return _items.IndexOf(itm); }
        }

        public IXFItem this[int itm]
        {
            get { return _items[itm]; }
        }

        public void ClearItem(int item)
        {
            if (item >= _items.Count)
                return;

            var itm = _items[item];
            _items.RemoveAt(item);

            itm.Dispose();
            Reset();
        }

        public void ClearItems()
        {
            foreach (var itm in _items)
                itm.Dispose();
            _items.Clear();
            Reset();
        }

        public void ClearItems(int start)
        {
            for (int i = start; i < _items.Count; i++)
            {
                _items[i].Dispose();
            }
            _items.RemoveRange(start, _items.Count - start);
            Reset();
        }

        public void ClearItems(int start, int count)
        {
            for (int i = start; i < start + count; i++)
            {
                _items[i].Dispose();
            }
            _items.RemoveRange(start, count);
            Reset();
        }

        public void ClearItemsAfterWaiting(XFItemLoading loading)
        {
            ClearItems(this[loading]);
        }

        public void ClearAnimationItem(IXFItem key)
        {
            if (!_animationItems.ContainsKey(key))
                return;

            var itm = _animationItems[key];
            _animationItems.Remove(key);

            itm.Dispose();
        }

        public override void ShowAlphaBar(bool show)
        {
            base.ShowAlphaBar(show);

            if (_alphabar != null)
            {
                _alphabar.LetterChanged += new XFPanelAlphabetBar.LetterChangedEventHandler(_alphabar_LetterChanged);
            }
        }

        public void Add(IXFItem item)
        {
            Add(item, _items.Count + 1);
        }

        public void Add(IXFItem item, int index)
        {
            if (item is XFItemBack)
                hasBack = true;

            if (item.State != XFItemState.Normal)
                item.State = XFItemState.Normal;

            int height = 0;

            if (item.Parent == null)
                item.Parent = this;

            if (index > _items.Count)
                _items.Add(item);
            else
                _items.Insert(index, item);
            foreach (var itm in _items)
            {
                height += itm.GetHeight();
            }
            setHeight(height);
        }

        public void Add(string item)
        {
            if (!string.IsNullOrEmpty(item))
                Add(new XFItemSimpleText(item) { Parent = this });
        }

        public void AddAnimation(XFItemAnimation item, IXFItem subItem)
        {
            if (!_items.Contains(subItem))
                return;

            _animationItems.Add(subItem, item);
        }

        public void AddHeaderItem(IXFItem item)
        {
            if (HeaderItem != null)
            {
                _items.Remove(HeaderItem);
                HeaderItem.Dispose();
            }
            if (item is XFItemBack)
                hasBack = true;

            int height = 0;

            if (item.Parent == null)
                item.Parent = this;

            _items.Insert(0, item);
            foreach (var itm in _items)
            {
                height += itm.GetHeight();
            }
            setHeight(height);

            HeaderItem = item;
        }

        public override void PanelPaint(Graphics g)
        {
            int curY = LocationY;
            bool rendered = false;
            bool animate = false;

            for (int i = 0; i < _items.Count; i++)
            {
                int curHeight = _items[i].GetHeight();

                if (curHeight == 0)
                    continue;

                if ((curY + curHeight) >= 0 && curY <= Screen.PrimaryScreen.WorkingArea.Height)
                {
                    rendered = true;

                    if (i != 0 || HeaderItem == null)
                    {
                        renderItemBuffer(_items[i]);
                        try
                        {
                            g.DrawImage(_items[i].Buffer, 0, curY);
                        }
                        catch (ObjectDisposedException) { }

                        if (renderAnimation(_items[i], g, curY))
                            animate = true;
                    }
                }
                else if (rendered) break;

                curY += curHeight;
            }

            _hasAnimation = animate;

            if (HeaderItem != null)
                HeaderItem.ItemPaint(g, 0, 0);
        }

        private bool renderAnimation(IXFItem item, Graphics g, int curY)
        {
            bool animate = false;
            if (_animationItems.ContainsKey(item))
            {
                animate = true;
                var anItem = _animationItems[item];

                anItem.Buffer = new Bitmap(Screen.PrimaryScreen.WorkingArea.Width, anItem.GetHeight());
                using (Graphics gb = Graphics.FromImage(anItem.Buffer))
                {
                    gb.Clear(Color.Purple);
                    anItem.ItemPaint(gb, 0, 0);
                }

                XFControlUtils.DrawAlphaFirstPix(g, anItem.Buffer, 0, curY);
                anItem.Buffer.Dispose();
                anItem.Buffer = null;
            }
            return animate;
        }

        private void renderItemBuffer(IXFItem item)
        {
            if (item.Buffer == null)
            {
                int h = item.GetHeight();
                if (h > 0)
                    item.Buffer = new Bitmap(Width, h);
                using (Graphics gr = Graphics.FromImage(item.Buffer))
                {
                    gr.Clear(BackColor);
                    item.ItemPaint(gr, 0, 0);
                }
            }
        }

        public void MoveToItem(IXFItem item)
        {
            if (_items.Contains(item))
            {
                var itm = _items.IndexOf(item);
                int curY = 0;

                for (int i = 0; i < itm; i++)
                {
                    curY += _items[i].GetHeight();
                }
                LocationY = -curY;

                Invalidate();
            }
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);

            switch (_curState)
            {
                case States.Click:
                    selectItem(e.X, e.Y);
                    Invalidate();
                    break;
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            switch (_curState)
            {
                case States.Click:
                    var itm = getSelectedItem();
                    if (itm == null)
                        return;

                    switch (itm.GetClickResult())
                    {
                        case XFItemClickResult.Nothing:
                            _curState = States.Idle;
                            break;
                        case XFItemClickResult.TextInput:
                            _curState = States.InsertText;
                            break;
                        case XFItemClickResult.SlideLeft:
                            _curState = States.SlideLeft;
                            break;
                        case XFItemClickResult.SlideRight:
                            _curState = States.SlideRight;
                            break;
                        case XFItemClickResult.CustomModal:
                            _curState = States.Modal;
                            break;
                    }

                    deselectItem();
                    break;
            }

            base.OnMouseUp(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            switch (_curState)
            {
                case States.Scroll:
                    deselectItem();
                    Invalidate();
                    break;
            }
        }

        private void deselectItem()
        {
            foreach (var itm in _items)
            {
                if (itm.ItemType == XFItemType.Display)
                    continue;

                if (itm.State == XFItemState.Selected && itm.ItemType != XFItemType.ClickableNonChange)
                {
                    if (itm.Buffer != null)
                        itm.Buffer.Dispose();
                    itm.Buffer = null;
                }
                itm.State = XFItemState.Normal;
            }

            if ((Attributes & PanelAttributes.Swipe) == PanelAttributes.Swipe)
                Attributes = Attributes ^ PanelAttributes.Swipe;
        }

        private void selectItem(int x, int y)
        {
            int curY = LocationY;

            if (HeaderItem != null)
            {
                if (y < _items[0].GetHeight())
                {
                    _items[0].State = XFItemState.Selected;

                    if (_items[0] is IXFItemReceiveClick)
                        ((IXFItemReceiveClick)_items[0]).GetClick(x, y);
                    return;
                }
            }

            for (int i = 0; i < _items.Count; i++)
            {
                int curHeight = _items[i].GetHeight();

                if (y > curY && y < curY + curHeight)
                {
                    if (_items[i].ItemType == XFItemType.Display)
                        return;
                    else if (_items[i].ItemType == XFItemType.Swipable)
                        Attributes |= PanelAttributes.Swipe;

                    if (_items[i].ItemType != XFItemType.ClickableNonChange)
                    {
                        if (_items[i].Buffer != null)
                            _items[i].Buffer.Dispose();
                        _items[i].Buffer = null;
                    }
                    _items[i].State = XFItemState.Selected;

                    if (_items[i] is IXFItemReceiveClick)
                        ((IXFItemReceiveClick)_items[i]).GetClick(x, y - curY);
                    return;
                }
                curY += curHeight;
            }
        }

        private IXFItem getSelectedItem()
        {
            foreach (var itm in _items)
            {
                if (itm.State == XFItemState.Selected)
                    return itm;
            }
            return null;
        }

        private void _alphabar_LetterChanged(char newLetter)
        {
            foreach (var item in _items)
            {
                if (item is XFItemSimpleText)
                {
                    XFItemSimpleText sText = (XFItemSimpleText)item;
                    if (sText.Text[0] == newLetter)
                    {
                        MoveToItem(item);
                        return;
                    }
                }
            }
        }

        private void setHeight(int height)
        {
            int fullScreen = Parent != null ? Parent.Height : Screen.PrimaryScreen.WorkingArea.Height;
            if (height < fullScreen)
                height = fullScreen;

            Height = height;
        }

        protected override void Dispose()
        {
            ClearItems();
            base.Dispose();
        }
    }
}
